package org.goj.practice.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.http.server.HttpServerResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.goj.common.constant.ResultCode;
import org.goj.common.entity.practice.Contest;
import org.goj.common.entity.practice.Problem;
import org.goj.common.model.Result;
import org.goj.feign.feign.BaseFeignClient;
import org.goj.practice.dto.SimpleContestProblemDTO;
import org.goj.practice.service.ContestService;
import org.goj.practice.service.ProblemService;
import org.goj.practice.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.OutputStream;
import java.util.List;

/**
 * <p>
 * 题目 前端控制器
 * </p>
 *
 * @author CK
 * @since 2020-12-02
 */
@RestController
@RequestMapping("/problem")
public class ProblemController {

    @Resource
    private ProblemService problemService;

    @Autowired
    private BaseFeignClient baseFeignClient;

    @Autowired
    private ContestService contestService;

    /**
     * 管理员添加题目
     *
     * @param problem 题目
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/25 16:00
     */
    @PostMapping("/addProblem")
    public Result<Boolean> insertProblem(@RequestBody @Valid Problem problem) {
        boolean flag = problemService.insertProblem(problem);
        Assert.isTrue(flag, "添加题目失败！");
        return Result.succeed("添加题目成功！", true);
    }

    /**
     * 管理员修改题目
     *
     * @param problem 题目实体
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/26 19:04
     */
    @PostMapping("/updateProblem")
    public Result<Boolean> updateProblem(@RequestBody @Valid Problem problem) {
        boolean flag = problemService.updateProblem(problem);
        Assert.isTrue(flag, "修改题目失败！");
        return Result.succeed("修改题目成功！", true);
    }

    /**
     * Markdown上传图片
     *
     * @param image 图片
     * @return Result<String>
     * @author CK
     * @date 2021/3/25 16:00
     */
    @PostMapping("addProblemImage")
    public Result<String> insertProblemImage(@RequestPart(value = "image") MultipartFile image) {
        return baseFeignClient.upload(image);
    }

    /**
     * Markdown删除图片
     *
     * @param url 图片路径
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/25 15:59
     */
    @PostMapping("deleteProblemImage")
    public Result<Boolean> deleteProblemImage(@RequestParam(value = "url") String url) {
        return baseFeignClient.delete(url);
    }

    /**
     * 根据题目ID修改题目状态
     *
     * @param problemId 题目ID
     * @param defunct   状态
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/26 14:53
     */
    @PostMapping("/updateDefunct")
    public Result<Boolean> updateDefunct(@RequestParam(value = "problemId") Integer problemId,
                                         @RequestParam(value = "defunct") String defunct) {
        defunct = "N".equals(defunct) ? "Y" : "N";
        Problem problem = new Problem();
        problem.setProblemId(problemId).setDefunct(defunct);
        boolean flag = problemService.updateById(problem);
        Assert.isTrue(flag, "修改状态失败！");
        return Result.succeed("修改状态成功", flag);
    }

    /**
     * 查看题目列表
     *
     * @param current        当前分页
     * @param size           分页大小
     * @param classifyIdList 分类列表
     * @param sort           排序方式
     * @return Result<Page < ProblemVO>>
     * @author CK
     * @date 2021/3/25 15:58
     */
    @GetMapping("/listProblem")
    public Result<Page<ProblemVO>> getProblemList(
            @RequestParam(value = "current", required = false, defaultValue = "1") Integer current,
            @RequestParam(value = "size", required = false, defaultValue = "10") Integer size,
            @RequestParam(value = "classifyIdList", required = false) List<Integer> classifyIdList,
            @RequestParam(value = "sort", required = false, defaultValue = "1") Integer sort,
            @RequestParam(value = "name", required = false) String name) {
        Page<ProblemVO> problemPageVO = problemService.getProblemConditionPage(current, size, classifyIdList, sort, name);
        return Result.succeed("查询题目成功！", problemPageVO);
    }

    /**
     * 管理员查看题目列表
     *
     * @param current        当前分页
     * @param size           分页大小
     * @param classifyIdList 分类列表
     * @param sort           排序方式
     * @param name           查询条件名
     * @return Result<Page < ProblemAdminVO>>
     * @author CK
     * @date 2021/3/25 15:59
     */
    @GetMapping("/listProblemAdmin")
    public Result<Page<ProblemAdminVO>> getProblemAdminList(
            @RequestParam(value = "current", required = false, defaultValue = "1") Integer current,
            @RequestParam(value = "size", required = false, defaultValue = "10") Integer size,
            @RequestParam(value = "classifyIdList", required = false) List<Integer> classifyIdList,
            @RequestParam(value = "sort", required = false, defaultValue = "1") Integer sort,
            @RequestParam(value = "name", required = false) String name) {
        Page<ProblemAdminVO> page = problemService.getProblemAdminPage(current, size, classifyIdList, sort, name);
        return Result.succeed("查询题目列表成功", page);
    }

    /**
     * 获取题目详情
     *
     * @param problemId 题目ID
     * @return Result<ProblemDetailsVO>
     * @author CK
     * @date 2021/3/25 15:59
     */
    @GetMapping("/problemById")
    public Result<ProblemDetailsVO> getProblemById(
            @RequestParam(value = "problemId") Integer problemId,
            @RequestParam(value = "contestId", required = false, defaultValue = "-1") Integer contestId) {
        Problem problem = problemService.getById(problemId);
        ProblemDetailsVO problemDetailsVO = new ProblemDetailsVO();
        //当题目为空或者不属于竞赛
        if (contestId == -1) {
            if (problem == null || !"N".equals(problem.getDefunct())) {
                return Result.failed(ResultCode.USER_ERROR_A0403.getCode(), ResultCode.USER_ERROR_A0403.getMessage());
            }
        } else {
            List<SimpleContestProblemDTO> list = problemService.listSimpleContestProblemDTO(contestId);
            Assert.isTrue(list.size() > 0, "查询竞赛列表失败");
            problemDetailsVO.setContestProblem(list);
            problemDetailsVO.setLanguage(contestService.getById(contestId).getLanguage());
        }
        BeanUtils.copyProperties(problem, problemDetailsVO);
        return Result.succeed("根据ID查询题目成功！", problemDetailsVO);
    }

    /**
     * 管理员根据题目ID获取题目信息
     *
     * @param problemId 题目ID
     * @return Result<ProblemDetailsAdminVO>
     * @author CK
     * @date 2021/3/26 17:32
     */
    @GetMapping("/problemAdminById")
    public Result<Problem> getProblemAdminById(@RequestParam(value = "problemId") Integer problemId) {
        Problem problem = problemService.getProblemAdminById(problemId);
        //当题目为空
        if (problem == null) {
            return Result.failed(ResultCode.USER_ERROR_A0403.getCode(), ResultCode.USER_ERROR_A0403.getMessage());
        }
        return Result.succeed("获取题目信息成功", problem);
    }

    /**
     * 管理员根据题目ID删除题目
     *
     * @param problemId 题目ID
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/26 15:51
     */
    @DeleteMapping("/deleteProblem")
    public Result<Boolean> deleteProblemById(@RequestParam(value = "problemId") Integer problemId) {
        boolean flag = problemService.deleteProblem(problemId);
        Assert.isTrue(flag, "删除题目失败");
        return Result.succeed("删除题目成功", flag);
    }

    /**
     * 添加题目测试数据
     *
     * @param problemId      题目ID
     * @param name           名称
     * @param inputTestData  输入数据
     * @param outputTestData 输出数据
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/28 18:13
     */
    @PostMapping("/addTestData")
    public Result<Boolean> addTestData(@RequestParam(value = "problemId") Integer problemId,
                                       @RequestParam(value = "name") String name,
                                       @RequestParam(value = "inputTestData", required = false) String inputTestData,
                                       @RequestParam(value = "outputTestData") String outputTestData) {
        Assert.isTrue(outputTestData.length() > 0, "输出数据是必填项");
        boolean flag = problemService.addTestData(problemId, name, inputTestData, outputTestData);
        Assert.isTrue(flag, "添加测试数据失败！");
        return Result.succeed("添加测试数据成功", flag);
    }

    /**
     * 根据题目ID获取测试数据
     *
     * @param problemId 题目ID
     * @return Result<TestDataVO>
     * @author CK
     * @date 2021/3/28 14:47
     */
    @GetMapping("/getTestData")
    public Result<List<TestDataVO>> getTestData(@RequestParam(value = "problemId") Integer problemId) {
        List<TestDataVO> testDataVO = problemService.getTestData(problemId);
        return Result.succeed("获取测试数据成功！", testDataVO);
    }

    /**
     * 根据数据名字前缀删除测试数据
     *
     * @param name      测试数据名
     * @param problemId 题目ID
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/28 17:08
     */
    @DeleteMapping("/deleteTestData")
    public Result<Boolean> deleteTestData(@RequestParam(value = "name") String name,
                                          @RequestParam(value = "problemId") Integer problemId) {
        Assert.isTrue(!"sample".equals(name) && !"test0".equals(name), "基础测试数据不可删除！");
        boolean flag = problemService.deleteTestData(name, problemId);
        Assert.isTrue(flag, "删除测试数据失败！");
        return Result.succeed("删除测试数据成功！", flag);
    }

    /**
     * 根据名字获取对应的数据
     *
     * @param name      名字
     * @param problemId 题目ID
     * @return Result<List < String>>
     * @author CK
     * @date 2021/3/28 19:11
     */
    @GetMapping("/getTestDataByName")
    public Result<List<String>> getTestDataByName(@RequestParam(value = "name") String name,
                                                  @RequestParam(value = "problemId") Integer problemId) {
        List<String> list = problemService.getTestDataByName(name, problemId);
        Assert.isTrue(list.size() == 2, "获取测试数据失败！");
        return Result.succeed("获取测试数据成功！", list);
    }

    /**
     * 根据名字和题目ID更新数据
     *
     * @param problemId      题目ID
     * @param name           名字
     * @param inputTestData  输入数据
     * @param outputTestData 输出数据
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/28 19:16
     */
    @PostMapping("/updateTestDataByName")
    public Result<Boolean> updateTestDataByName(@RequestParam(value = "problemId") Integer problemId,
                                                @RequestParam(value = "name") String name,
                                                @RequestParam(value = "inputTestData", required = false) String inputTestData,
                                                @RequestParam(value = "outputTestData") String outputTestData) {
        Assert.isTrue(outputTestData.length() > 0, "输出数据是必填项");
        boolean flag = problemService.updateTestDataByName(name, problemId, inputTestData, outputTestData);
        Assert.isTrue(flag, "更新测试数据失败！");
        return Result.succeed("更新测试数据成功！", flag);
    }

    /**
     * 导入题目
     *
     * @param file 题目文件
     * @return Result<Boolean>
     * @author CK
     * @date 2021/3/31 16:44
     */
    @PostMapping("/uploadProblem")
    public Result<List<UploadProblemVO>> uploadProblem(@RequestPart(value = "file") MultipartFile file) {
        List<UploadProblemVO> list = problemService.uploadProblem(file);
        Assert.isTrue(list.size() > 0, "导入题目失败");
        return Result.succeed("导入题目成功", list);
    }

    /**
     * 查询简要题目数据
     *
     * @param current 当前页
     * @param size    所有页
     * @param sort    排序
     * @return Result<Page < SimpleProblemVO>>
     * @author CK
     * @date 2021/5/11 16:37
     */
    @GetMapping("/simpleProblemPage")
    public Result<Page<SimpleProblemVO>> simpleProblemPage(
            @RequestParam(value = "current", required = false, defaultValue = "1") Integer current,
            @RequestParam(value = "size", required = false, defaultValue = "10") Integer size,
            @RequestParam(value = "sort", required = false, defaultValue = "1") Integer sort) {
        Page<SimpleProblemVO> page = problemService.pageSimpleProblem(current, size, sort);
        return Result.succeed("查询成功", page);
    }

    /**
     * 下载题目,下载xml文件格式不对，留待解决
     *
     * @param problemIds 题目ID集合
     * @return void
     * @author CK
     * @date 2021/5/11 16:57
     */
    @GetMapping("/downloadProblem")
    public void downloadProblem(@RequestParam(value = "problemIds") List<Integer> problemIds) {
        problemService.downloadProblem(problemIds);
    }

}

